package com.shanshan.wheel.rpc.common.remoting.transport.clent;

import com.shanshan.wheel.rpc.ApplicationContextUtil;
import com.shanshan.wheel.rpc.common.compress.CompressType;
import com.shanshan.wheel.rpc.common.remoting.constant.RpcMessageType;
import com.shanshan.wheel.rpc.common.remoting.dto.RpcMessage;
import com.shanshan.wheel.rpc.common.remoting.dto.RpcResponse;
import com.shanshan.wheel.rpc.common.serialize.SerializationType;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

/**
 * @Description
 * @ClassName NettyRpcClientHandler
 * @Author 山山大魔王
 * @Date 2022/9/5 11:34
 * @Version 1.0
 */
@Slf4j
public class NettyRpcClientHandler extends SimpleChannelInboundHandler<RpcMessage> {

    private final UnprocessedRequests unprocessedRequests;

    public NettyRpcClientHandler(){
        ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
        unprocessedRequests = applicationContext.getBean(UnprocessedRequests.class);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcMessage msg) throws Exception {
        log.info("客户端接收消息:[{}]", msg);
        // 判断消息类型是否是心跳响应PONG消息
        if(msg.getMessageType() == RpcMessageType.HEARTBEAT_PONG_TYPE.getCode()){
            log.info("心跳 [{}]", msg.getData());
        }else {
            RpcResponse<Object> response = (RpcResponse) msg.getData();
            // 收到回复，在unprocessedRequest中移除请求，并将结果放入future中，调用方就可通过该future获取rpc调用结果了
            unprocessedRequests.complete(response);
        }
    }

    /**
     * 监听用户事件
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 判断是否为IdleStateEvent
        if(evt instanceof IdleStateEvent){
              IdleStateEvent event = (IdleStateEvent) evt;
              // 判断是否为一段时间没有发送数据而触发的
              if(event.state() == IdleState.WRITER_IDLE){
                  // 构建心跳PING消息
                  RpcMessage rpcMsg = RpcMessage.builder()
                          .compress(CompressType.GZIP.getCode())
                          .codec(SerializationType.KRYO.getCode())
                          .data("PING")
                          .messageType(RpcMessageType.HEARTBEAT_PING_TYPE.getCode())
                          .build();
                  // 发送数据
                  ctx.writeAndFlush(rpcMsg).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
              }
        }else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("client catch exception：", cause);
        cause.printStackTrace();
        ctx.close();
    }
}
